package com.itaming.lycheeframework.support.cipher;

import com.itaming.lycheeframework.support.utils.ArrayUtil;
import org.springframework.util.Assert;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import java.security.NoSuchAlgorithmException;

/**
 * 加解密器抽象类
 *
 * @author A.Ming
 */
public abstract class AbstractEncryptor<T extends Encryptor.Options> implements Encryptor<T> {

    /**
     * 初始化{@link Cipher}实例
     *
     * @param instance   Cipher实例
     * @param cipherMode 加解密模式，加密：{@link Cipher#ENCRYPT_MODE}，解密：{@link Cipher#DECRYPT_MODE}
     * @param options    加密器选项
     * @throws Exception
     */
    protected abstract void initCipherInstance(Cipher instance, int cipherMode, T options) throws Exception;

    /**
     * 加解密
     *
     * @param encryptMode 加解密模式，加密：{@link Cipher#ENCRYPT_MODE}，解密：{@link Cipher#DECRYPT_MODE}
     * @param data        待加密数据
     * @param options     加密器选项
     * @return 加解密后的数据，待加密数据为空时原样返回
     */
    protected byte[] doFinal(int encryptMode, byte[] data, T options) {
        if (ArrayUtil.isEmpty(data)) {
            return data;
        }

        Cipher instance = getInstance(options.getFullAlgorithm());
        try {
            initCipherInstance(instance, encryptMode, options);
            return instance.doFinal(data);
        } catch (Exception e) {
            throw new IllegalArgumentException("Could not encrypt or decrypt data: " + e.getMessage(), e);
        }
    }

    /**
     * 获取算法实例
     *
     * @param algorithm 算法
     * @return 算法实例
     */
    protected Cipher getInstance(String algorithm) {
        try {
            return Cipher.getInstance(algorithm);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new IllegalArgumentException("Could not find Cipher with algorithm \"" + algorithm + "\"", e);
        }
    }

    /**
     * 检查加密器选项
     *
     * @param options 选项
     */
    protected void checkOptions(T options) {
        Assert.notNull(options, "Encryptor options must not be null");
    }

}
